'''
Created on Mar 23, 2011

@author: mwarren1
'''
import wx
from wx.tools.dbg import Logger
from threading import Timer, Thread
import time, os
import subprocess
import maildroplibs
from maildroplibs import Counter
import TaskBarIcon

# Removed b/c can't find win32print module :(
#if 'wxMSW' in wx.PlatformInfo:
#    from printlibs.winPrinter import Printing
#else:
#    from printlibs.NullPrinter import Printing
#

debug = Logger('MailThread')
debug.SetStream(maildroplibs.DEBUGSTREAM)
debug(enable = maildroplibs.ENABLEDEBUG)


def pause():
    for mthread in MailThread.instanceList:
        mthread.pause()
        
def unpause():
    for mthread in MailThread.instanceList:
        mthread.unpause()
        
def resetConnections():
    for mthread in MailThread.instanceList:
        mthread.resetConnections()

def stop():
    MailThread.CANCEL = True
    debug("All Email Check Threads will be Cancelled at Next Interval")
    debug("Class CANCEL: " + str(MailThread.CANCEL))
    debug("Instanced Running: " + str(MailThread.instanceList))
    for mthread in MailThread.instanceList:
        mthread.cancel()
        del mthread

class MailThread(object):
    '''
    classdocs
    '''

    CANCEL = False
    instanceList = []

    def __init__(self, settings):
        '''
        Constructor
        '''
        self.settings = settings
        self.initial = True
        # self.imap = maildroplibs.ImapConnector(self.settings)
        self.timer = None
        self.__RESETTING = False
        self.__PAUSE = False
        self.__CANCEL = False
        self.__class__.instanceList.append(self)
        self.idleList = dict()
               
    def __del__(self):
        self.cancel()
        self.__class__.instanceList.remove(self)
        
    def check(self):
        ''' Connect to Gmail's IMAP Server '''    
        imap = maildroplibs.ImapConnector(self.settings)
        
        try:
            if imap.connect():

                success = True
                doExit = False

                ''' Read and Download Messages '''

                debug('Labels to check: ' + str(self.settings['LABELDICT'].items()))
                for label, info in self.settings['LABELDICT'].items():  
                    folder = info[0]
                    overwrite = info[1]   
                    commands = info[2] 

                    dlList = []
                    keepList = set()

                    debug('Checking ' + label)      

                    try:
                        messages = imap.getMessages(label)
                        downloader = maildroplibs.ImapDownloader(self.settings, messages)
                        downloader.listMessagesAttachments()

                        success1, list1, keepList1 = downloader.downloadLinks(folder, overwrite)
                        success2, list2, keepList2 = downloader.downloadAttachments(folder, overwrite)

                        success = success and success1 and success2

                        dlList.extend(list1)
                        dlList.extend(list2)

                        keepList = set(keepList1) | set(keepList2)
                    # TypeError Occurs when application is closed in the middle of
                    # checking for emails. Since the application is exciting, we
                    # don't really care if it completes the download or not,
                    # so we just ignore(pass) this.
                    except TypeError as e:
                        print "An Error Has Occurred (Ignoring for now): \n" + str(e)
                        pass

                    if maildroplibs.TYPE:
                        doExit = self.execCommands(commands, dlList) or doExit
                    imap.clearMessages(label, keepList)
                
                    downloader.__del__() 
                '''Logout '''
                imap.disconnect()

                if doExit:
                    print "Exiting MailDrop"
                    debug("Exiting MailDrop: Exit called by label command")
                    TaskBarIcon.exit()
                    return
                                
                if success and not (self.__CANCEL or self.__class__.CANCEL):     
                    TaskBarIcon.setToolTip("Last Run: " + time.strftime("%c"), TaskBarIcon.NORMAL_ICON)
                else:
                    TaskBarIcon.setToolTip("Error Running MailDrop\nPlease Check Settings", TaskBarIcon.ERROR_ICON)
                
                    
            else:
                print "MailDrop Failed to Connect to " + self.settings['EMAILSERVER']
                TaskBarIcon.setToolTip("Error Running MailDrop\nPlease Check Settings", TaskBarIcon.ERROR_ICON)
        
        except Exception as e:
            debug.log(str(e))
            if str(e).index("Application-specific password") > -1:
                print "YOU NEED TO USE AN APPLICATION SPECIFIC PASSWORD!"
                TaskBarIcon.setToolTip("Login Failed:\nApplication-Specific Password Required", TaskBarIcon.ERROR_ICON)
                wx.MessageDialog(None, str(e), "MailDrop: Login Failed", wx.OK|wx.ICON_HAND).ShowModal()
            raise e
            
            
        imap.__del__()
        
    def execCommands(self, commands, files):
        doExit = False
        for file in files:
            folder, filename = os.path.split(file)
            for command in commands.splitlines():
                if command.startswith('#'):
                    continue
                if command.lower() == 'print':
                    try:
                        print "Printing " + filename
                        printer = Printing()
                        printer.printFile(file)
                    except Exception as e:
                        print str(e)
                        debug(str(e))
                elif command.lower() == 'delete':
                    try:
                        print "Deleting " + filename
                        os.remove(file)
                    except Exception as e:
                        print str(e)
                        debug(str(e))
                elif command.lower() == 'exit':
                    doExit = True
                else:
                    command = command.replace('%filename', '"'+filename+'"')
                    try:
                        print "Running Command " + command
                    except:
                        print "Running Command"
                    try:
                        subprocess.call(command, shell=True, cwd=folder)
                    except Exception as e:
                        debug(str(e))
                        print e
                        
        return doExit            
        
        
    def start(self):
        
        if not self.__PAUSE:
            try:
                self.settings.verify()
                
                if self.__inLimit():
                    TaskBarIcon.setToolTip("Checking Email...", TaskBarIcon.NORMAL_ICON)
                    checkThread = Thread(target=self.check, name="Check-Thread")
                    debug("Starting checkThread")
                    checkThread.start()
                    debug("Waiting for checkThread to finish")
                    checkThread.join()

                Counter.save()             
                
            except maildroplibs.SettingsError as e:
                self.pause()
                TaskBarIcon.setToolTip("Error Running MailDrop\nPlease Check Settings", TaskBarIcon.ERROR_ICON)
                e.showError()

        if not (self.__CANCEL or self.__class__.CANCEL):
            debug("Finished checkThread, restarting timer")
            self.timer = Timer(self.settings['CHECKINTERVAL']*60,self.start)
            self.timer.start()
                
    def pause(self): self.__PAUSE = True
    def unpause(self): self.__PAUSE = False
    
    
    def resetConnections(self):
        ''' For Standard Connections '''
        self.cancel()
        self.__CANCEL = False
        self.start()
        ''' For Idle Connections ONLY 
        #If another thread is initiating reset,
        #quit attemt on this thread
        if self.__RESETTING:
            return
        self.__RESETTING = True
        debug.log("At this point we should try reconnecting (every minute or so...)")
        #time.sleep(60)
        debug.log("Resetting idle-ness")
        self.cancel() #Disconnect
        self.__CANCEL = False
        self.idlestart() #Reconnect '''
        
    
    def cancel(self):
        debug("Cancelling Interval Checking")
        self.__CANCEL = True
        if self.timer is not None:
            self.timer.cancel()
        for label, imap in self.idleList.items():
            try:
                print "Stopping : " + label
            except:
                pass
            print imap
            imap.stopIdle()
            imap.disconnect()
            imap.__del__()
            if label in self.idleList:
                del self.idleList[label]
            
    def __inLimit(self):
        if maildroplibs.TYPE:
            return maildroplibs.TYPE
        if time.strftime("%m%d%Y") != Counter.getItem('DATE'):
            Counter.setItem('DATE', time.strftime("%m%d%Y"))
            Counter.setItem('COUNT', 0)
        if Counter.getItem('COUNT') <= Counter.getItem('LIMIT'):
            return True
        else:
            debug("Skipping Mail Check: Reached Daily Limit")
            print "Skipping Mail Check: Reached Daily Limit"
            TaskBarIcon.setToolTip("Reached Daily Limit", TaskBarIcon.NOCONN_ICON)
            return False
